package com.vvv.designpattern.controller;

import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.vvv.designpattern.constants.Constants;
import com.vvv.designpattern.pojo.Order;
import com.vvv.designpattern.service.OrderService;
import com.vvv.designpattern.service.decorator.OrderServiceDecorator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @author vvv
 * @date 2023-11-21 13 28
 * discription
 * =====================================================================================
 * 订单状态转换业务流程：
 *
 * 流程是：用户发起了请求，请求先到controller，然后到service，
 * 状态模式：如果service中这个请求执行成功，那么我们发event告诉spring状态机订单状态需要被转换，并在redis中保存状态机的状态
 * 观察者模式：spring状态机将状态转化后会发通知给Listener
 * 命令模式：Listener 通过命令模式将订单状态转化后的操作，如将订单信息保持到redis和数据库，给业务部门发mq等待
 *
 * 比如：现在订单的状态是待支付状态
 * 1. controller 支付宝回调支付成功后的接口
 * 2. service 支付成功，发event给spring状态机，
 * 3. 状态机里面维护的状态：待支付状态 -> 待发货状态，状态机发消息给Listener
 * 3. Listener修改redis中的订单的状态为：待支付状态 -> 待发货状态，通过调用命令模式作后序处理
 * 4. 命令模式将订单信息写入db，发mq给相关部门
 *
 *=========================================================================================
 * 多种类支付业务：
 *  首先用于先调用create创建订单
 *  买家账号：ngfrfd0761@sandbox.com
 *  密码：111111
 *
 *  发起支付请求流程：
 *  1. controller 用户发起/pay支付请求
 *  2. service getPayUrl方法，通过orderId先去redis中获取订单信息，然后调用门面模式的pay方法
 *  3. payFacade 门面模式通过payContextFactory工厂类获取策略类上下文对象PayContext
 *  4. PayContextFactory 工厂类用于缓存和创建PayContext对象
 *  5. PayContext 门面模式拿到策略上下文对象后，调用PayContext的execute方法，这个方法就是调用具体策略类的pay方法，
 *          具体策略类也是在PayContextFactory创建并缓存起来的
 *  6. AlipayStrategy 具体策略类填入相关请求参数向支付宝发起支付请求
 *  7. 支付宝返回支付的url连接
 *
 *  支付完成后回调流程：
 *  1. controller 支付宝调用我们向支付宝发起支付请求时填写的回调地址/alipaycallback
 *  2. service 如果判断是支付宝对这个/alipaycallback发起的请求后，我们再去判断是否支付成功，支付成功去service中修改订单状态/pay方法
 *  3. 返回修改后的订单状态信息给前端
 *  =========================================================================================
 *  朋友代付：
 *  1. service通过中介者模式去向朋友发通知
 *  2. 中介者是全局唯一的，中介者中用map缓存了代支付者，和支付者
 *  ======================================================================================
 *  订单审计日志：
 *  1. 通过模板模式实现
 * */
@RestController
@RequestMapping("/order")
public class OrderController {

    @Resource
    private OrderService orderService;

    @Resource
    private OrderServiceDecorator orderServiceDecorator;

    @Value("${service.level}")
    private Integer serviceLevel;

    @PostMapping("/friendPay")
    public void friendPay(String sourceCustomer, String orderId
            , String targetCustomer, String payResult, String role) {
        orderService.friendPay(sourceCustomer, orderId, targetCustomer, payResult, role);
    }

    @PostMapping("/create")
    public Order createOrder(@RequestParam String productId) {
        return orderService.createOrder(productId);
    }

    @PostMapping("/pay")
    public String payOrder(@RequestParam String orderId,
                          @RequestParam Float price,
                          @RequestParam Integer payType) {
        return orderService.getPayUrl(orderId, price, payType);
    }

    @PostMapping("/send")
    public Order sendOrder(@RequestParam String orderId) {
        return orderService.send(orderId);
    }

    @PostMapping("/receive")
    public Order receiveOrder(@RequestParam String orderId) {
        return orderService.receive(orderId);
    }

    @RequestMapping("/alipaycallback")
    public String alipayCallback(HttpServletRequest request)
            throws UnsupportedEncodingException, AlipayApiException {
        // 获取回调信息
        Map<String, String> params = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = iter.next();
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
            params.put(name, valueStr);
        }
        // 验证签名，确保接口是支付宝调用的
        boolean signVerified = AlipaySignature.rsaCheckV1(params
                , Constants.ALIPAY_PUBLIC_KEY, "UTF-8", Constants.SIGN_TYPE);
        if (signVerified) {
            String out_trade_no = new String(request.getParameter("out_trade_no")
                    .getBytes("ISO-8859-1"), "UTF-8");
            String trade_no = new String(request.getParameter("trade_no")
                    .getBytes("ISO-8859-1"), "UTF-8");
            float total_amount = Float.parseFloat(new String(request.getParameter("total_amount")
                    .getBytes("ISO-8859-1"), "UTF-8"));
            // 进行相关的业务操作，将订单状态改为待发货状态
            orderServiceDecorator.setOrderService(orderService);
            Order order = orderServiceDecorator.decoratorPay(out_trade_no, serviceLevel, total_amount);
            return "支付成功页面跳转，当前订单为：" + order;
        } else {
            throw new UnsupportedOperationException("callback verify failed! ");
        }
    }
}
